import TushareModule from "./TushareModule";
import FileModule from "./FileModule";
import LogModule from "./LogModule";
import TimeModule from "./TimeModule";

const {ccclass, property} = cc._decorator;

var isUpLimit = function (data) {
    if (data.close == data.up_limit && data.close == data.high) {
        return true;
    }
    return false;
}

const UpLimitType = 99;

@ccclass
export default class MatchModule {

    public mainZb: any = {};

    //长期横盘 连续2-3个板 放量 但是不大 有大阴线 缩量调整 同时调整量大于横盘量 热门板块 这种票选入股池
    //筛选过程
    //1. 60个交易日内 是否有2次以上涨停 
    //2. 最近1年 波动不大于100%
    //3. 涨停那天成交量 不大于之前成交量的2倍
    matchUpLimit (dailys: any, total: number, upCount: number, upLimitType: number) {
        let upLimitFlag = upLimitType == 99;
        let upLimitCount = 0; 
        let upLimitContinue = 0;
        let isContinue = true;

        //统计连板次数
        for (let index = 0; index < dailys.length; index++) {
            const daily = dailys[index];
            if (isContinue && isUpLimit(daily)) {
                upLimitContinue++;
            } else {
                isContinue = false;
                break;
            }
        }

        if (total > dailys.length) {
            total = dailys.length;
        }

        for (let index = 0; index < total; index++) {
            const daily = dailys[index];
            if (upLimitFlag) {
                if (isUpLimit(daily)) {
                    upLimitCount++;
                }
            } else {
                if (daily.pre_close) {
                    let rate = (daily.close - daily.pre_close) / daily.pre_close * 100;
                    if (rate > upLimitType) {
                        upLimitCount++;
                    }
                }
            }
        }
        
        let result = {
            upLimitCount: upLimitCount, 
            upLimitContinue: upLimitContinue, 
            isMatch: upLimitCount >= upCount,
        };
        return result;
    }

    //匹配振幅
    matchFloat (dailys: any, total: number, float: number) {
        if (dailys.length < total) return false;
        let high = 0, low = 0;
        for (let index = 0; index < total; index++) {
            const item = dailys[index];
            if (item.high_qfq > high) {
                high = item.high_qfq;
            }

            if (low == 0) {
                low = item.low_qfq;
            } else if (item.low_qfq < low) {
                low = item.low_qfq;
            }
        }

        let floatRate = Math.floor((high - low) / low * 100);
        return floatRate < float;
    }

    //匹配成交量 在特定日期
    matchVolume (dailys: any, total, min, max, count) {
        if (count >= total) {
            count = total;
        }
        let matchCount = 0;
        for (let index = total; index > 0; index--) {
            const day1 = dailys[index];
            const day2 = dailys[index - 1];
            let volume = day2.vol / day1.vol;
            if (volume >= min && volume <= max) {
                matchCount++;
            }
        }
        return matchCount >= count;
    }

    //匹配换手率
    matchTurnRate (dailys: any, total, min, max, ts_code) {
        let module = TushareModule.getInstance();
        let mark = module.dailyMarket[ts_code];
        let totalShare = mark.float_share * 100;
        for (let index = 0; index < total; index++) {
            const day = dailys[index];
            let rate = Math.floor(day.vol / totalShare * 100);
            if (rate < min || rate > max) {
                return false;
            }
        }
        return true;
    }

    matchUpFloat (dailys: any, total, upFloatMin, upFloatMax) {
        let baseIndex = total + 1;
        if (baseIndex > dailys.length - 1) {
            baseIndex = dailys.length - 1;
        }

        let preClose = dailys[baseIndex].close_qfq;
        let nowClose = dailys[0].close_qfq;

        let trueFloat = (nowClose - preClose) / preClose * 100;
        if (trueFloat >= upFloatMin && trueFloat <= upFloatMax) {
            return true;
        }
        return false;
    }

    //对比市值 单位亿
    matchShizhi (ts_code, min, max) {
        let module = TushareModule.getInstance();
        let mark = module.dailyMarket[ts_code];
        if (mark && mark.total_mv >= (min * 10000) && mark.total_mv <= (max * 10000)) {
            return true;
        }
        return false;
    }

    //对比上市时间
    matchIssueDate (ts_code, min, max) {
        let module = TushareModule.getInstance();
        let today = parseInt(TimeModule.getInstance().strToday());
        let onLineTime = module.stockInfo[ts_code].list_date;
        let inv = Math.floor((today - parseInt(onLineTime)) / 100);
        if (inv >= min && inv <= max) {
            return true;
        }
        return false;
    }

    //匹配特殊类型
    matchOtherType (dailys: any, otherType) {
        switch (otherType) {
            case 1: {
                return this.matchAllRed(dailys);
            }
            case 2: {
                return this.matchVolumeUp(dailys);
            }
            case 3: {
                return this.matchAllRedUp(dailys);
            }
            default: {
                return true;
            }
        }
    }

    //持续阳线
    matchAllRed (dailys: any) {
        for (let index = 0; index < dailys.length - 1; index++) {
            const day = dailys[index];
            if (day.close <= day.open) {
                return false;
            }
        }
        return true;
    }

    //持续放量
    matchVolumeUp (dailys: any) {
        for (let index = 0; index < dailys.length - 3; index++) {
            const day = dailys[index];
            const day2 = dailys[index + 2];
            if (day.vol < day2.vol) {
                return false;
            }
        }
        return true;
    }

    //持续阳线
    matchAllRedUp (dailys: any) {
        for (let index = 0; index < dailys.length - 1; index++) {
            const day = dailys[index];
            if (day.close < day.pre_close) {
                return false;
            }
        }
        return true;
    }

    async loadStockDaily (dates) {
        let module = TushareModule.getInstance();
        let stockDailyMap = {};
        for (let index = 0; index < dates.length; index++) {
            const date = dates[index];
            let list = await module.getTotalStockDaily(date);
            for (let j = 0; j < list.length; j++) {
                const daily = list[j];
                let ts_code = daily.ts_code;
                if (stockDailyMap[ts_code] == null) {
                    stockDailyMap[ts_code] = [];
                }
                stockDailyMap[ts_code].push(daily);
            }
        }
        return stockDailyMap;
    }

    async matchStock (condition, searchStocks) {
        let module = TushareModule.getInstance();

        let oldStocks:any = await FileModule.loadJsonAsync("match_stock_boshi");
        if (oldStocks == null) {
            oldStocks = [];
        }
        LogModule.log('准备拉取日线行情');
        let dates = TimeModule.getInstance().getRecentTradeDates(condition.tradeDayCnt + 1);
        let stockDailyMap = await this.loadStockDaily(dates);

        let stocks = [];
        let list = module.stockList;
		
		if (condition.searchInResult) {
			list = searchStocks;
		}
		
        for (let index = 0; index < list.length; index++) {
            const item = list[index];
            let ts_code = item.ts_code;
            let name = item.name;
            let info = module.stockInfo[ts_code];

            let isMatch = true;

            //去除st
            if (condition.removeSt) {
                isMatch = (name.indexOf('st') == -1 && name.indexOf('ST') == -1);
                if (isMatch == false) continue;
            }
            
            //去除创业板
            if (condition.onlyZhuban) {
                isMatch = module.isZhuBan(ts_code);
                if (isMatch == false) continue;
            }

            if (info == null) {
                continue;
            }

            //对比股东数量
            if (info.holder_nums) {
                isMatch = (info.holder_nums >= (condition.ownerMin * 10000) && info.holder_nums <= (condition.ownerMax * 10000));
                if (isMatch == false) continue;
            }

            //对比上市时间
            isMatch = this.matchIssueDate(ts_code, condition.issueDateMin, condition.issueDateMax);
            if (isMatch == false) continue;

            //对比市值
            isMatch = this.matchShizhi(ts_code, condition.szMin, condition.szMax);
            if (isMatch == false) continue;

            let dailys = stockDailyMap[ts_code];
            //去除今日涨停
            if (condition.removeLastLimitUp) {
                let result = this.matchUpLimit(dailys, 1, 1, UpLimitType);
                isMatch = result.isMatch;
                if (isMatch == true) {
                    continue;
                }
            }

            //对比涨停数量
            let result = this.matchUpLimit(dailys, dailys.length - 1,condition.upLimitCnt, condition.upLimitType);
            isMatch = result.isMatch;
            if (isMatch == false) continue;

            //对比换手率
            isMatch = this.matchTurnRate(dailys, dailys.length - 1, condition.hsMin, condition.hsMax, ts_code);
            if (isMatch == false) continue;

            //对比量能
            isMatch = this.matchVolume(dailys, dailys.length - 1, condition.volumeMin, condition.volumeMax, condition.volumeCount);
            if (isMatch == false) continue;
            
            isMatch = this.matchUpFloat(dailys, dailys.length - 1, condition.upFloatMin, condition.upFloatMax);
            if (isMatch == false) continue;

            //特殊类型对比
            if (condition.otherType > 0) {
                isMatch = this.matchOtherType(dailys, condition.otherType);
                if (isMatch == false) continue;
            }

            let market = module.dailyMarket[ts_code];
            let stock = {
                ts_code: ts_code, 
                name: name, 
                market: market, 
                listDate: item.list_date, 
                upLimitCount: result.upLimitCount, 
                upLimitContinue: result.upLimitContinue,
                upLimitType: condition.upLimitType,
            };
            stocks.push(stock);
        }
        LogModule.log('匹配股票完成,找到股票' + stocks.length + '个');
        return stocks;
    }

    async matchStockLimit (condition) {
        let module = TushareModule.getInstance();
        let tradeCount = condition.tradeDayCnt;
        if (tradeCount < 15) {
            tradeCount = 15;
        }
        let dates = TimeModule.getInstance().getRecentTradeDates(tradeCount);
        let stockDailyMap = await this.loadStockDaily(dates);

        let stocks = [];
        let list = module.stockList;
       
        for (let index = 0; index < list.length; index++) {
            const item = list[index];
            let ts_code = item.ts_code;
            let name = item.name;
            LogModule.log('正在匹配股票:' + name);
            let isMatch = true;
            let dailys = stockDailyMap[ts_code];
            if (dailys == null || dailys.length == 0) {
                continue;
            }
            //只搜索今日涨停
            if (condition.todayLimit) {
                let result = this.matchUpLimit(dailys, 1, 1, UpLimitType);
                isMatch = result.isMatch;
                if (isMatch == false) continue;
            }

            //去除st
            if (condition.removeSt) {
                isMatch = (name.indexOf('st') == -1 && name.indexOf('ST') == -1);
                if (isMatch == false) continue;
            }

            //去除创业板
            if (condition.onlyZhuban) {
                isMatch = module.isZhuBan(ts_code);
                if (isMatch == false) continue;
            }

            //对比涨停数量
            let result = this.matchUpLimit(dailys, condition.tradeDayCnt, 1, condition.upLimitType);
            isMatch = result.isMatch;
            if (isMatch == false) continue;

            let market = module.dailyMarket[ts_code];
            let stock = {
                ts_code: ts_code, 
                name: name, 
                market: market, 
                listDate: item.list_date, 
                upLimitCount: result.upLimitCount, 
                upLimitContinue: result.upLimitContinue,
                upLimitType: condition.upLimitType,
            };
            stocks.push(stock);
        }

        LogModule.log('找到股票:' + stocks.length + '个');

        stocks.sort(function (a, b) {
            if (a.upLimitCount == b.upLimitCount) {
                return b.upLimitContinue - a.upLimitContinue;
            }
            return b.upLimitCount - a.upLimitCount;
        });

        return stocks;
    }

    async matchStockDaysRank (condition) {
        let module = TushareModule.getInstance();
        let tradeCount = condition.tradeDayCnt;
        let dates = TimeModule.getInstance().getRecentTradeDates(tradeCount);
        let stockDailyMap = await this.loadStockDaily(dates);

        let stocks = [];
        let list = module.stockList;
       
        for (let index = 0; index < list.length; index++) {
            const item = list[index];
            let ts_code = item.ts_code;
            let name = item.name;
            LogModule.log('正在匹配股票:' + name);
            let isMatch = true;
            let dailys = stockDailyMap[ts_code];
            if (dailys == null || dailys.length == 0) {
                continue;
            }

            //去除st
            if (condition.removeSt) {
                isMatch = (name.indexOf('st') == -1 && name.indexOf('ST') == -1);
                if (isMatch == false) continue;
            }

            //去除创业板
            if (condition.onlyZhuban) {
                isMatch = module.isZhuBan(ts_code);
                if (isMatch == false) continue;
            }

            let preClose = dailys[dailys.length - 1].pre_close_qfq;
            let close = dailys[0].close_qfq;

            let upFloat = Math.floor((close - preClose) / preClose * 10000) / 100;

            let market = module.dailyMarket[ts_code];
            let stock = {
                ts_code: ts_code, 
                name: name, 
                market: market, 
                listDate: item.list_date, 
                upFloat: upFloat, 
                tradeCount: tradeCount,
            };
            stocks.push(stock);
        }

        stocks.sort(function (a, b) {
            if (condition.upRank) {
                return b.upFloat - a.upFloat;
            } else {
                return a.upFloat - b.upFloat;
            }
        });

        stocks = stocks.slice(0, condition.total); 
        return stocks;
    }

    async getLitteCompany () {
        var JsonType = TushareModule.JsonType;
        let bestCompany: any = await FileModule.loadJsonAsync(JsonType.BestCompany);
        let litte = [];

        let strCompany = [];
        let strLitter = [];

        let strBig = [];

        for (let index = 0; index < bestCompany.length; index++) {
            const item = bestCompany[index];
            let info = item.info;
            let mark = item.market;
            let strItem = `${info.ts_code} ${info.name} pe:${mark.pe} pettm:${mark.pe_ttm} 市值:${mark.total_mv}万元 营业增长率:${info.saleRate} 利润增长率:${info.incomeRate}`;
            strCompany.push(strItem);

            if (item.market.total_mv < 2000000) {
                strLitter.push(strItem);
                litte.push(item);
            } else {
                strBig.push(strItem);
            }
        }
        await FileModule.saveJsonAsync(JsonType.LitteBest + '_2', strLitter, 100);
        await FileModule.saveJsonAsync(JsonType.LitteBest, litte, 100);
        await FileModule.saveJsonAsync(JsonType.BestCompany + '_2', strCompany, 100);

        await FileModule.saveJsonAsync('big_company', strBig, 100);
    }

}